#!/usr/bin/env python
from __future__ import unicode_literals
from __future__ import absolute_import

import time
from sqlalchemy import and_
from ..models import Host, Item, History, History_str, Graph, Graph_item
from ..utils import highcharts
from .. import get_db


class BaseOrmInterface(object):
    def __init__(self, session=None, limit=10, period=600, stime=None,
                 itemid=0, etime=None):
        self.session = session if session else self.db_session()
        self.history_tables = {0: History, 1: History_str}
        self.limit = limit + 1
        self.period = period
        self.stime = int(stime) if stime else int(time.time() - self.period)
        self.etime = int(etime) if etime else self.stime + self.period
        self.itemid = itemid

    def db_session(self):
        db = get_db()
        if not db:
            raise Exception("Not get sqlalchemy session object")
        return db

    def limit_process(self, data):
        length = len(data)
        jump_num = length / self.limit
        if jump_num < 1:
            return data
        return sorted(sorted(data, reverse=True, key=lambda x: x.clock)[
            ::jump_num], key=lambda x: x.clock)

    def delta_process(self, item, data):
        '''
        Difference is according to the data(s1 - s)
        data index of one (data init is zero, timestamp is (
        index num - (index num + 1 - index num))
        s is data item
        index num is list index num
        '''
        new_data = []
        if len(data) < 2:
            return data
        if item.delta == 1:
            length = len(data)
            for i in range(length):
                if i == (length - 1):
                    break
                new_data.append(data[i + 1] - data[i])
            # debug
            # print len(new_data), item, length, self.limit
            return new_data
        return data[:-1]


class history(BaseOrmInterface):
    def get(self, item):
        avg = self.period / self.limit
        table = self.history_tables.get(item.value_type)
        result = self.session.query(table).filter(and_(
            table.itemid == item.itemid,
            table.clock > self.stime - avg,
            table.clock < self.etime
        )).all()
        result = self.limit_process(result)
        result = self.delta_process(item, result)
        return result


class item(BaseOrmInterface):
    def get(self, itemid):
        return self.session.query(Item).get(itemid)


class graph(BaseOrmInterface):
    def get_host(self, hostid):
        graphs = self.session.query(Graph).filter(Graph.hostid == hostid).all()
        return [g.graphid for g in graphs]

    def get_items(self, graphid):
        graph_data = self.session.query(Graph).get(graphid)
        if not graph_data:
            '''if graphid not exists  return is null dict'''
            return {}

        graph_item_data = self.session.query(Graph_item).filter(
            Graph_item.graphid == graph_data.graphid).all()
        itemid = []
        for i in graph_item_data:
            itemid.append(i.itemid)
        return {graph_data.name: itemid}

    def highcharts_render_data(self, graphid):
        '''
        {'series': [itemhistory1, itemhistory2], time}
        '''
        data = {'series': []}
        items = self.get_items(graphid)
        # exception process
        name = items.keys()[0]
        history_i = history(self.session, limit=self.limit,
                            period=self.period, stime=self.stime,
                            etime=self.etime)
        item_i = item(self.session)
        data['title'] = {"text": name, "x": -20}
        for itemid in items[name]:
            item_data = item_i.get(itemid)
            history_data = history_i.get(item_data)
            series = {}
            series['data'] = map(lambda x: [int(x.clock * 1000),
                                            float('%.2f' % x.value)],
                                 history_data)
            series['name'] = item_data.name
            data['series'].append(series)
        return (name, items[name], highcharts(data))

    def get_data(self, graphid):
        items = self.get_items(graphid)
        key = items.keys()[0]
        data = {key: {'data': [], 'itemids': map(int, items[key])}}
        h = history(self.session, limit=self.limit, period=self.period,
                    stime=self.stime)
        i = item(self.session)
        for itemid in items[key]:
            h_item = i.get(itemid)
            h_value = h.get(h_item)
            item_data = {'name': h_item.name}
            item_data['data'] = map(lambda x:
                                    [int(x.clock * 1000),
                                     float('%.2f' % float(x.value))],
                                    h_value)
            data[key]['data'].append(item_data)
        return data


class host(BaseOrmInterface):
    def __init__(self, session=None):
        BaseOrmInterface.__init__(self, session)
        self.info_keys = ['redis_version', 'redis_mode', 'role',
                          'uptime_in_seconds', 'process_id',
                          'connected_slaves']

    def get(self, hostid):
        return self.session.query(Host).get(hostid)

    def all(self):
        return self.session.query(Host).filter(Host.status == 0).all()

    def info(self, hostid):
        items = []
        values = {}
        nhost = self.get(hostid)
        print nhost, hostid
        key = nhost.hostid
        values[key] = {}
        for ik in self.info_keys:
            item_data = self.session.query(Item).filter(
                and_(Item.hostid == hostid, Item.key_ == ik)).all()
            if not item_data:
                continue
            items.append(item_data[0])
        h = history(self.session, period=(3600 * 24), limit=1)
        for ik1 in items:
            ik_v = h.get(ik1)
            if not ik_v:
                values[key][ik1.key_] = None
            else:
                if not isinstance(ik_v[0].value, unicode):
                    ik_v[0].value = int(ik_v[0].value)
                values[key][ik1.key_] = ik_v[0].value
        return values
